/* Copyright 2001,2002,2003 NAH6 BV
 * All Rights Reserved
 *
 *  $Header: /var/lib/cvs/secphone/ui/phone/Vibrator.cpp,v 1.5 2003/11/21 16:12:58 itsme Exp $
 *
 *
 * implement various vibrating modes
 *
 */

#include  <windows.h>
#include  <nled.h>

#include  "nhThread.h"
#include  "debug.h"

#include "Vibrator.h"


// from the platform builder <Pwinuser.h>
extern "C" {
BOOL WINAPI NLedGetDeviceInfo( UINT     nInfoId, void   *pOutput );
BOOL WINAPI NLedSetDevice( UINT nDeviceId, void *pInput );
};

void LedOn(int id)
{
    NLED_SETTINGS_INFO settings;
    settings.LedNum= id;
    settings.OffOnBlink= 1;
    NLedSetDevice(NLED_SETTINGS_INFO_ID, &settings);

    //debug("VIB: on\n");
}
void LedOff(int id)
{
    NLED_SETTINGS_INFO settings;
    settings.LedNum= id;
    settings.OffOnBlink= 0;
    NLedSetDevice(NLED_SETTINGS_INFO_ID, &settings);

    //debug("VIB: off\n");
} 

// implementation of vibrator class

Vibrator::Vibrator()
{
    // automatic, initially non signalled event
    m_hChangeEvent= CreateEvent(0, FALSE, FALSE, NULL);

    // state
    m_state= STATE_OFF;
    m_metastate= META_OFF;
    m_metacycle= 0;

    // parameters
    m_mode= MODE_OFF;
    m_onMsec= 0;
    m_offMsec= 1000;
    m_onCycles= 0;
    m_offCycles= 1;

    m_lednr= 1; // this is hardware dependent
}

Vibrator::~Vibrator()
{
}


void Vibrator::on()
{
    m_mode= MODE_ON;
    m_onMsec= 1000;
    m_offMsec= 0;
    m_onCycles= 1;
    m_offCycles= 0;
    SetEvent(m_hChangeEvent);
}

void Vibrator::off()
{
    m_mode= MODE_OFF;
    m_onMsec= 0;
    m_offMsec= 1000;
    m_onCycles= 0;
    m_offCycles= 1;
    SetEvent(m_hChangeEvent);
}

void Vibrator::blink(int onMsec, int offMsec)
{
    if (onMsec==0 && offMsec==0)
    {
        debug("ERROR: invalid parameters to Vibrator::blink\n");
        return;
    }
    m_mode= MODE_BLINK;
    m_onMsec= onMsec;
    m_offMsec= offMsec;
    m_onCycles= 1;
    m_offCycles= 0;
    SetEvent(m_hChangeEvent);
}

void Vibrator::metablink(int onMsec, int offMsec, int onCycles, int offCycles)
{
    if ((onCycles==0 && offCycles==0) || (onMsec==0 && offMsec==0))
    {
        debug("ERROR: invalid parameters to Vibrator::metablink\n");
        return;
    }
    m_mode= MODE_BLINK;
    m_onMsec= onMsec;
    m_offMsec= offMsec;
    m_onCycles= onCycles;
    m_offCycles= offCycles;
    SetEvent(m_hChangeEvent);
}


DWORD Vibrator::ThreadProc()
{
    while (true)
    {
        DWORD wait;
        if (m_mode==MODE_OFF)
            wait= INFINITE;
        else if (m_mode==MODE_ON)
            wait= INFINITE;
        else if (m_mode==MODE_BLINK && m_state==STATE_OFF)
            wait= m_offMsec;
        else if (m_mode==MODE_BLINK && m_state==STATE_ON)
            wait= m_onMsec;
        else
        {
            wait= INFINITE;
            debug("ERROR: invalid mode or state in vibrator\n");
        }

        if ( m_state==STATE_ON && m_metastate==META_ON )
            LedOn(m_lednr);
        else
            LedOff(m_lednr);

        DWORD res= WaitForSingleObject(m_hChangeEvent, wait);
        if (res==WAIT_OBJECT_0)
        {
            // new mode is signalled
            //debug("VIB: new state: mode=%d\n", m_mode);

            if (m_mode==MODE_OFF)
            {
                m_state= STATE_OFF;
                m_metastate= META_OFF;
                m_metacycle= 0;
            }
            else if (m_mode==MODE_ON)
            {
                m_state= STATE_ON;
                m_metastate= META_ON;
                m_metacycle= 0;
            }
            else if (m_mode==MODE_BLINK)
            {
                m_state= STATE_ON;
                m_metastate= m_onCycles?META_ON:META_OFF;
                m_metacycle= 0;
            }
            else {
                debug("ERROR: invalid mode in vibrator\n");
                m_state= STATE_OFF;
                m_metastate= META_OFF;
                m_metacycle= 0;
            }
        }
        else if (res==WAIT_TIMEOUT)
        {
            //debug("VIB: next state (state=%d)\n", m_state);

            if (m_state==STATE_ON)
                m_state= STATE_OFF;
            else if (m_state==STATE_OFF)
                m_state= STATE_ON;
            else
            {
                debug("ERROR: invalid state in vibrator\n");
                m_state= STATE_OFF;
            }

            // handle meta cycle
            if (m_state==STATE_ON)
            {
                m_metacycle++;
                if (m_metastate==META_OFF && m_metacycle>=m_offCycles)
                {
                    m_metastate= m_onCycles?META_ON:META_OFF;
                    m_metacycle= 0;
                }
                else if (m_metastate==META_ON && m_metacycle>=m_onCycles)
                {
                    m_metastate= m_offCycles?META_OFF:META_ON;
                    m_metacycle= 0;
                }
            }
        }
        else {
            // thread terminating
            break;
        }
    }
    LedOff(m_lednr);

    return 0;
}



